package org.codetranslators.tools.XMLUtils;

import java.util.Iterator;
import java.util.Vector;

import org.codetranslators.common.Temp;
import org.codetranslators.compiler.intermrep.AssemblyInstruction;
import org.codetranslators.compiler.intermrep.CJump;
import org.codetranslators.compiler.intermrep.Call;
import org.codetranslators.compiler.intermrep.Jump;
import org.codetranslators.compiler.intermrep.LabelInstr;
import org.codetranslators.compiler.intermrep.Operation;

import org.dom4j.Attribute;
import org.dom4j.Element;

public class XmlToAssemblyInstruction {
	
	public static final int INSTRUCTION = 10	;
	public static final int JUMP = 20;
	public static final int CJUMP = 30;
	public static final int CALL = 40;
	public static final int LABEL = 50;
	public static final int SSA_PHI_FUNCTION = 60;
	public static final int ADD = 0;
	public static final int MINUS = 1;
	public static final int MUL = 2;
	public static final int DIV = 3;
	public static final int LOAD_IMMEDIATE_VALUE = 4;
	public static final int STORE_WORD_INTO_ADDRESS_AT_TEMP = 5;
	public static final int STORE_WORD_INTO_CONST_ADDRESS = 6;
	public static final int MOVE_TEMP_TO_TEMP = 7;
	public static final int LOAD_ADDRESS = 8;
	public static final int LOAD_FROM_TEMP_OFFSET_EXP_MEM = 9;
	
	int i;
	
	public  AssemblyInstruction getInstruction(Element element,String type, Vector useIntructions, Vector defInstructions){
		
		System.out.println("called assembly Instruction");
		
		int instructionType = getInstructionType(type);
		
		Vector useTemps = getuseTemps(useIntructions);
		Vector defTemps = getDefTemps(defInstructions);		
		
		
		if(instructionType == JUMP){
			return getJumpInstruction(element);
		}
		else if(instructionType == CJUMP){
			return getCJumpInstruction(element,useTemps);
		}
		else if(instructionType == CALL){
			return getCallInstruction(element);
		}
		else if(instructionType == LABEL){
			return getLabelInstruction(element);
		}
		else{
			return getOperationInstruction(element,type,defTemps,useTemps);
		}		
		
	}
	
	
	
	public  Jump getJumpInstruction(Element element){
		Iterator attributeIterator = element.attributeIterator();
		
		String label = null;
		String jumpString ="\t" + "j " + "\n" + "\r\n";
		
		while(attributeIterator.hasNext()){
			Attribute attribute = (Attribute)attributeIterator.next();
			
			if("label".equalsIgnoreCase(attribute.getQualifiedName())){
				label = attribute.getValue();
			}
		}
		
		if(label!=null)	{	
			Jump jump = new Jump(jumpString,label);			
			return jump;
		}
		else{
			return null;
		}
		
	}
	public   CJump getCJumpInstruction(Element element,Vector useIntructions){
		Iterator attributeIterator = element.attributeIterator();
		
		String ifLabel = null;
		String elseLabel = null;
		int relop = -1 ;
		Integer immediateValue = null; 
		
		while(attributeIterator.hasNext()){
			Attribute attribute = (Attribute)attributeIterator.next();
			
			if("ifLabel".equalsIgnoreCase(attribute.getQualifiedName())){
				ifLabel = attribute.getValue();
			}
			else if("falseLabel".equalsIgnoreCase(attribute.getQualifiedName())){
				elseLabel = attribute.getValue();
			}
			else if("relop".equalsIgnoreCase(attribute.getQualifiedName())){
				relop = getRelationalInt(attribute.getValue());
			}
			else if("im".equalsIgnoreCase(attribute.getQualifiedName())){
				try{
					immediateValue = Integer.parseInt(attribute.getValue());
				}
				catch(Exception ex){
					System.out.println("error in cjump XmlToAssemblyInstruction");
					immediateValue = 0;
				}
			}
		}
		
		if(ifLabel !=null && elseLabel!=null && relop!= -1)	{	
			CJump cjump = new CJump(useIntructions,ifLabel,elseLabel,relop,immediateValue);
			return cjump;
		}
		else{
			return null;
		}
		
	}
	
	public  LabelInstr getLabelInstruction(Element element){
		Iterator attributeIterator = element.attributeIterator();
		String assemCode = null;
		String label = null;
		
		while(attributeIterator.hasNext()){
			Attribute attribute = (Attribute)attributeIterator.next();
			if("ins".equalsIgnoreCase(attribute.getQualifiedName())){
				assemCode = attribute.getValue();
			}
			else if("label".equalsIgnoreCase(attribute.getQualifiedName())){
				label = attribute.getValue();
			}
		}
		if(assemCode!=null && label!=null){
			LabelInstr labelInstr = new LabelInstr(assemCode,label);
			return labelInstr;
		}	
		return null;
		
	}
	
	public  Call getCallInstruction(Element element){
		Iterator attributeIterator = element.attributeIterator();
		String fname = null;
		String str;
		
		while(attributeIterator.hasNext()){
			Attribute attribute = (Attribute)attributeIterator.next();
			
			if("fname".equalsIgnoreCase(attribute.getQualifiedName())){
				fname = attribute.getValue();
			}
		}
		str =  "\t" + "jal " + fname + "\n";
		Call call = new Call(fname,str);
		return call;	
		
	}
	
	public  Operation getOperationInstruction(Element element,String type,Vector destList, Vector srcList){
		
		int instructionType = getInstructionType(type);
		Operation op = null;
		Integer immediateValue = null; 
		Iterator attributeIterator = element.attributeIterator();
		while(attributeIterator.hasNext()){
			Attribute attribute = (Attribute)attributeIterator.next();
			if("im".equalsIgnoreCase(attribute.getQualifiedName())){
				immediateValue = Integer.parseInt(attribute.getValue());
			}
		}
		try{
		
		if(instructionType == ADD){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == MINUS){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == MUL){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == DIV){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == LOAD_IMMEDIATE_VALUE){
			op = new Operation(destList,null,instructionType,immediateValue,null);
		}
		else if(instructionType == STORE_WORD_INTO_ADDRESS_AT_TEMP){
			op = new Operation(null,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == STORE_WORD_INTO_CONST_ADDRESS){
			op = new Operation(null,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == MOVE_TEMP_TO_TEMP){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == LOAD_ADDRESS){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}
		else if(instructionType == LOAD_FROM_TEMP_OFFSET_EXP_MEM){
			op = new Operation(destList,srcList,instructionType,immediateValue,null);
		}		
		
		return op;
		}
		catch(Exception ex){
			ex.printStackTrace();
		}
		return op;
	}
	
	public   int getInstructionType(String type){
		
		if("JUMP".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.JUMP;
		}
		else if("CJUMP".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.CJUMP;
		}
		else if("CALL".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.CALL;
		}
		else if("LABEL".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.LABEL;
		}
		else if("ADD".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.ADD;
		}
		else if("MINUS".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.MINUS;
		}
		else if("MUL".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.MUL;
		}
		else if("DIV".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.DIV;
		}
		else if("LOAD_IMMEDIATE_VALUE".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.LOAD_IMMEDIATE_VALUE;
		}
		else if("STORE_WORD_INTO_ADDRESS_AT_TEMP".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.STORE_WORD_INTO_ADDRESS_AT_TEMP;
		}
		else if("STORE_WORD_INTO_CONST_ADDRESS".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.STORE_WORD_INTO_CONST_ADDRESS;
		}
		else if("MOVE_TEMP_TO_TEMP".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.MOVE_TEMP_TO_TEMP;
		}
		else if("LOAD_ADDRESS".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.LOAD_ADDRESS;
		}
		else if("LOAD_FROM_TEMP_OFFSET_EXP_MEM".equalsIgnoreCase(type)){
			return XmlToAssemblyInstruction.LOAD_FROM_TEMP_OFFSET_EXP_MEM;
		}
		return 0;
		
	}
	
	public  int getRelationalInt(String value){
		if(value.equals("EQ")){
			return CJump.EQ;
		}
		else if(value.equals("NE")){
			return CJump.NE;
		}
		else if(value.equals("LT")){
			return CJump.LT;
		}
		else if(value.equals("GT")){
			return CJump.GT;
		}
		else if(value.equals("LE")){
			return CJump.LE;
		}
		else if(value.equals("GE")){
			return CJump.GE;
		}
		else if(value.equals("ULT")){
			return CJump.ULT;
		}
		else if(value.equals("ULE")){
			return CJump.ULE;
		}
		else if(value.equals("UGT")){
			return CJump.UGT;
		}
		else if(value.equals("UGE")){
			return CJump.UGE;
		}
		return -1;
	}
	public  Vector getuseTemps(Vector useInstructions){
		String s1 = null;
		Vector useTemps = new Vector();
		//System.out.println("size of use instructions is -----------------------"+useInstructions.size());
		Temp temp = null;
		for(Object o1:useInstructions){
			s1 = (String)o1;
			 temp = new Temp(i,s1);
			useTemps.add(temp);
		}
		return useTemps;
	}
	public  Vector getDefTemps(Vector defInstructions){
		String s1 = null;
		Vector defInsts = new Vector(defInstructions);		
		Vector defTemps  = new Vector();
		//System.out.println("size of def instructions is -----------------------"+defInstructions.size());
		Temp temp = null;
		for(Object o1:defInstructions){
			s1 = (String)o1;
			 temp = new Temp(i,s1);
			 defTemps.add(temp);
		}
		return defTemps;
		
	}
}
